package com.dream21th.oauth.controller;

import com.dream21th.oauth.common.LoginDTO;
import com.dream21th.oauth.remote.AdminFeign;
import com.dream21th.common.ComResp;
import com.dream21th.common.constants.Constants;
import com.dream21th.common.dto.UserTokenDTO;
import com.dream21th.common.enums.RtnEnum;
import com.dream21th.common.utils.MapperUtils;
import com.dream21th.common.utils.OkHttpClientUtil;
import com.dream21th.common.utils.RSAUtils2;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@RestController
public class LoginController {

    private static final String URL_OAUTH_TOKEN = "http://localhost:9001/oauth/token";

    @Value("${business.oauth2.grant_type}")
    public String oauth2GrantType;

    @Value("${business.oauth2.client_id}")
    public String oauth2ClientId;

    @Value("${business.oauth2.client_secret}")
    public String oauth2ClientSecret;

    @Value("${key.rsa.decode.private_key}")
    private String rsaPrivateKey;

    @Autowired
    @Qualifier("userDetailsServiceImpl")
    public UserDetailsService userDetailsService;

    @Resource
    public BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public TokenStore tokenStore;

    @Autowired
    public AdminFeign adminFeign;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @PostMapping("/user/login")
    public ComResp login(@RequestBody LoginDTO loginDTO){
        try {
            String password =RSAUtils2.decrytDataString(loginDTO.getPassword(), rsaPrivateKey);
            loginDTO.setPassword(password);
        } catch (Exception e) {
            return new ComResp().result(RtnEnum.PASSWORD_PARSE_ERROR);
        }
        String captcha =(String) redisTemplate.opsForValue().get(loginDTO.getUuid());
        if(Objects.isNull(captcha) || !StringUtils.equals(captcha,loginDTO.getCaptcha())){
            return new ComResp().result(RtnEnum.CAPTCHA_ERROR);
        }
        // 验证密码是否正确
        UserDetails userDetails = userDetailsService.loadUserByUsername(loginDTO.getUserName());
        if (userDetails == null || !passwordEncoder.matches(loginDTO.getPassword(), userDetails.getPassword())) {
            return new ComResp().result(RtnEnum.LOGIN_ERROR);
        }

        ComResp<UserTokenDTO> loginTokenResp = adminFeign.queryUserLoginToken(loginDTO.getUserName());
        String loginToken= Optional.ofNullable(loginTokenResp.getResponseData()).orElseGet(UserTokenDTO::new).getToken();
        if(Objects.nonNull(loginToken)){
            try {
                OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(loginToken);
                tokenStore.removeAccessToken(oAuth2AccessToken);
            }catch (Exception e){
                e.printStackTrace();
                log.info("token{}已失效",loginToken);
            }
        }
        // 通过 HTTP 客户端请求登录接口
        Map<String, String> params = Maps.newHashMap();
        params.put("username", loginDTO.getUserName());
        params.put("password", loginDTO.getPassword());
        params.put("grant_type", oauth2GrantType);
        params.put("client_id", oauth2ClientId);
        params.put("client_secret", oauth2ClientSecret);
        try {
            // 解析响应结果封装并返回
            Response response = OkHttpClientUtil.getInstance().postData(URL_OAUTH_TOKEN, params);
            String jsonString = Objects.requireNonNull(response.body()).string();
            Map<String, Object> jsonMap = MapperUtils.json2map(jsonString);
            String token = String.valueOf(jsonMap.get("access_token"));
            ComResp comResp = adminFeign.saveUserLoginToken(UserTokenDTO.builder().username(loginDTO.getUserName()).token(token).build());
            if(comResp.getCode().equals(Constants.SUCCESS)){
                return new ComResp<String>().data(token).success();
            }else{
                return new ComResp().result(RtnEnum.ERRROR);
            }
        } catch (Exception e) {
            return new ComResp().result(RtnEnum.ERRROR);
        }
    }


    @PostMapping(value = "/user/logout")
    public ComResp logout(HttpServletRequest request) {
        // 获取 token
        String token = request.getHeader("authorization");
        // 删除 token 以注销
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(StringUtils.substringAfter(token,"Bearer "));
        tokenStore.removeAccessToken(oAuth2AccessToken);
        return new ComResp().success();
    }
}
